﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Threading.Tasks;
using WeDonekRpc.Client.Attr;
using WeDonekRpc.Client.Interface;
using WeDonekRpc.Client.Log;
using WeDonekRpc.Client.Model;
using WeDonekRpc.Helper;

namespace WeDonekRpc.Client.EventBus
{
    public delegate void LocalEventComplete ( object sender, LocalEventArgs e );
    /// <summary>
    /// 本地事件
    /// </summary>
    internal class LocalEvent
    {
        /// <summary>
        /// 本地事件器
        /// </summary>
        private readonly Dictionary<string, ILocalHandler> _Handlers = [];
        /// <summary>
        /// 处理事件委托
        /// </summary>
        private event Action<object, string> _HandleEvent;

        private LocalComplateEvent _CompleteEvent = null;

        private static readonly Interface.IIocService _Ioc = RpcClient.Ioc;
        /// <summary>
        /// 事件名称
        /// </summary>
        public string EventName
        {
            get;
        }
        private readonly string _Key;
        public LocalEvent ( string name, string key )
        {
            this._Key = key;
            this.EventName = name;
        }
        /// <summary>
        /// 发布事件
        /// </summary>
        /// <param name="arg">事件参数</param>
        /// <param name="name">事件名</param>
        public void Post ( object arg )
        {
            if ( this._HandleEvent != null )
            {
                this._ExecAction(arg);
            }
        }
        /// <summary>
        /// 异步发布事件
        /// </summary>
        /// <param name="arg">事件参数</param>
        public void AsyncPost ( object arg )
        {
            if ( this._HandleEvent != null )
            {
                _ = Task.Factory.StartNew(() =>
                {
                    using ( IScoreService scope = _Ioc.CreateScore() )
                    {
                        this._ExecAction(arg);
                    }
                });
            }
        }
        /// <summary>
        /// 执行委托队列
        /// </summary>
        /// <param name="arg"></param>
        private void _ExecAction ( object arg )
        {
            ErrorException error = null;
            try
            {
                this._HandleEvent(arg, this.EventName);
            }
            catch ( Exception e )
            {
                error = ErrorException.FormatError(e);
                error.Args.Add("Body", arg.ToJson());
                error.Args.Add("Key", this._Key);
                if ( !error.Args.ContainsKey("Name") )
                {
                    error.Args.Add("Name", this.EventName);
                }
                error.SaveLog("LocalEvent");
            }
            finally
            {
                this._Complete(arg, error);
            }
        }
        private void _Complete ( object arg, ErrorException error )
        {
            if ( this._CompleteEvent == null )
            {
                return;
            }
            try
            {
                this._CompleteEvent.Completed(arg, this.EventName, error);
            }
            catch ( Exception e )
            {
                ErrorException ex = ErrorException.FormatError(e);
                error.Args.Add("Body", arg.ToJson());
                ex.SaveLog("LocalEvent");
            }
        }
        public void RegCompleteEvent ( Type type, string name )
        {
            if ( this._CompleteEvent == null )
            {
                this._CompleteEvent = new LocalComplateEvent(type, name);
            }
            else
            {
                throw new ErrorException("rpc.local.event.complate.reg.repeat")
                {
                    Args = new System.Collections.Generic.Dictionary<string, string>
                    {
                        {"Name",name },
                        {"Type",type.FullName }
                    }
                };
            }
        }
        /// <summary>
        /// 注册
        /// </summary>
        /// <param name="type"></param>
        /// <param name="name"></param>
        /// <returns></returns>
        public void Reg ( Type type, string name )
        {
            if ( this._Handlers.ContainsKey(name) )
            {
                return;
            }
            int sort = 100;
            if ( type.GetCustomAttribute(typeof(LocalEventSort), true) is LocalEventSort t )
            {
                sort = t.Sort;
            }
            if ( !this._Handlers.TryAdd(name, new LocalEventHandler(type, name, sort)) )
            {
                string show = string.Format("key:{0}, name:{1}, to:{2}, toName:{3}", this._Key, this.EventName, type.FullName, name);
                RpcLogSystem.AddLog("本地事件注册失败!", show);
            }
        }
        public bool Build ()
        {
            if ( this._Handlers.Count > 0 )
            {
                foreach ( ILocalHandler item in this._Handlers.Values.OrderBy(a => a.Sort) )
                {
                    _HandleEvent += item.HandleEvent;
                }
                return true;
            }
            return false;
        }
    }
}
